import { NodePath } from '@babel/traverse'
import { ClassDeclaration, ClassMethod } from '@babel/types'
import { preseComment } from './common'
import { ClassTypes, methodsInfoTypes, propertiesInfoTypes } from '../types/class'
import { resolveReturnType, resolveType } from './type'
import { Type } from '../utils/giveTypeAnswer'
import { Annotation } from 'doctrine'

export function generateClassProperty(generate: (content: propertiesInfoTypes) => void, path: NodePath<ClassDeclaration>) {
  path.traverse({
    ClassProperty(path) {
      const content = {
        name: path.get('key').toString(),
        // @ts-ignore
        type: resolveType(path.getTypeAnnotation()),
        doc: [path.node.leadingComments, path.node.trailingComments]
          .filter(Boolean)
          .map(item => {
            return preseComment(item?.values as unknown as string)
          })
          .filter(Boolean),
      } as propertiesInfoTypes
      generate(content)
    },
  })
}

export function generateClassMethod(generate: (constructorInfo: ClassTypes['constructorInfo'] | null, methodInfo: methodsInfoTypes | null) => void, path: NodePath<ClassDeclaration>) {
  path.traverse({
    ClassMethod(node) {
      if (node.node.kind === 'constructor') {
        generate(generateConstructor(node), null)
      } else {
        generate(null, generateMethod(node))
      }
    },
  })
}

function generateConstructor(path: NodePath<ClassMethod>) {
  return {
    params: path.get('params').map(paramsPath => {
      const info: { name: string; type: Type; doc?: undefined | Annotation } = {
        name: paramsPath.toString(),
        // @ts-ignore
        type: resolveType(paramsPath.getTypeAnnotation()),
      }
      if (path.node.leadingComments) info.doc = preseComment(path.node.leadingComments[0].value)
      return info
    }),
  }
}

export function generateMethod(path: NodePath<ClassMethod>) {
  return {
    name: path.get('key').toString(),
    doc: path.node.leadingComments && preseComment(path.node.leadingComments[0].value),
    // @ts-ignore
    return: resolveType(path.getTypeAnnotation()),
    params: path.get('params').map(paramPath => {
      return {
        name: paramPath.toString(),
        // @ts-ignore
        type: resolveReturnType(paramPath.getTypeAnnotation()),
      }
    }),
  }
}
/**
 * @description get method desc in class
 * @param methodInfo
 * @returns
 */
export function methodDescription(methodInfo: methodsInfoTypes): string {
  if (!methodInfo.doc) return ''
  const cur = methodInfo.doc?.tags.find(tagItem => tagItem.title === 'description')
  if (!cur) return ''
  if (!cur?.description) return ''
  return cur?.description
}
